package org.third.integration.ldap;

import com.sun.jndi.ldap.LdapName;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ActiveDirectoryPageTest {

    static String searchBase = "DC=adfshpe,DC=com";
    static String searchFilter = "(&(name=*))";

    static final Logger logger = LoggerFactory.getLogger(ActiveDirectoryPageTest.class);

    public static final void activeDirectoryQueryTest(Hashtable env) {
        searchBase = "DC=adfshpe,DC=com";
        searchFilter = "(&(objectClass=group)(mail=*))";
        LdapContext ctx = null;
        try {

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);

            SearchControls searchCtls = new SearchControls();
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            String returnedAtts[] = null;// { "sn", "givenName", "mail" };
            searchCtls.setReturningAttributes(returnedAtts);

           Attributes attrs1= ctx.getAttributes("CN=ouuser1 hpe,OU=Test OU 1,DC=adfshp,DC=com", new String[]{}); //no attributes
           System.out.println(attrs1);
           
           Attributes attrs3= ctx.getAttributes("CN=ouuser1 hpe,OU=Test OU 1,DC=adfshp,DC=com", null);  //retrieve all
           System.out.println(attrs3);
           
           Attributes attrs2= ctx.getAttributes("CN=ouuser1 hpe,OU=Test OU 1,DC=adfshp,DC=com", new String[]{"ssAMAccountName"});
           System.out.println(attrs2);
           

           String dn="CN=ouuser1 hpe,OU=Test OU 1,DC=adfshp,D C=com";
           String unAttrib="ssAMAccountName";
           try {
               
               String[] attribFilter = new String[] { unAttrib };
               Attributes ldapAttribs = ctx.getAttributes(dn, attribFilter);
               Attribute ldapAttrib = ldapAttribs.get(unAttrib);
               if (ldapAttrib == null) {
                   logger.debug("User's " + unAttrib + " attribute is null");
               }
               String upn = (String) ldapAttrib.get();
               logger.trace("User's Username = " + upn);
           } catch(NamingException ex) {
               logger.warn("Cannot get {} attribute for {}", unAttrib, dn.toString());
           }
           
            
            NamingEnumeration answer = null;
            try {
                answer = ctx.search(searchBase, searchFilter, searchCtls);
            } catch (NamingException e) {
                if (logger.isTraceEnabled()) {
                    logger.error("Unable to find group", e);
                } else {
                    logger.error("Unable to find group");
                }
                logger.debug("No ldap group found according to the parameters provided");
            }

            if (answer != null) {
                while (answer.hasMoreElements()) {

                    SearchResult sr = null;
                    try {
                        sr = (SearchResult) answer.next();
                    } catch (NamingException e) {
                        logger.error("Failed to search ldap", e);
                    }

                    System.out.println("name: " + sr.getName());

                    if (sr != null) {
                        String ldapGroupKey = sr.getNameInNamespace();
                        Enumeration vals = LdapUtil.getValuesFromAttrs(sr);
                        HashSet<String> members = new HashSet<String>();
                        if (vals != null) {
                            while (vals.hasMoreElements()) {

                                String userKey = (String) vals.nextElement();
                                members.add(userKey.toLowerCase());
                                logger.debug("Username: " + userKey);
                            }
                        } else {
                            logger.debug("No values found in the attributes list in search result for the group");
                        }
                    } else {
                        logger.debug("No search result found for the group");
                    }
                }
            } else {
                logger.debug("Search in Ldap returned null");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ctx.close();
            } catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }

    public static final void activeDirectoryPagedQueryTest(Hashtable env) {
//        searchBase="sAMAccountName=gongyo1,DC=ADFSHPE,DC=COM";
        searchBase="CN=group1,CN=Users,DC=adfshpe,DC=com";
//        searchBase="CN=Propel_AD_ConsumerUsersBigGroup3Peons,OU=Propel,OU=Applications,OU=TSLabs,DC=BEL1,DC=global,DC=tslabs,DC=hpecorp,DC=net";
        LdapContext ctx = null;
        try {

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);
            // Create the search controls
            SearchControls searchCtls = new SearchControls();

            // Specify the attributes to return
//            name:group1
//            instanceType:4
//            groupType:-2147483646
//            objectSid:
//            sAMAccountType:268435456
//            member:CN=user1100,CN=Users,DC=adfshpe,DC=com
//            uSNCreated:45832
//            uSNChanged:49184
//            objectClass:top
//            distinguishedName:CN=group1,CN=Users,DC=adfshpe,DC=com
//            objectCategory:CN=Group,CN=Schema,CN=Configuration,DC=adfshpe,DC=com
//            sAMAccountName:group1
//            objectGUID:
//            cn:group1
//            whenCreated:20161012074052.0Z
//            whenChanged:20161012074314.0Z
//            dSCorePropagationData:16010101000000.0Z
//            name: , size=0
//            >>Next Page 
//
//            Total entries: 1

//            String returnedAtts[] = {"member;Range=1-100","uniqueMember", "memberOf"};
            String returnedAtts[] =  {"member;range=0-100" };
            searchCtls.setReturningAttributes(returnedAtts);
//            searchCtls.setReturningAttributes(null);

            // Specify the search scope
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            // Set the page size and initialize the cookie that we pass back in subsequent pages
            int pageSize = 100;
            byte[] cookie = null;

            // Request the paged results control
//            Control[] ctls = new Control[] { new PagedResultsControl(pageSize, false) };
//            ctx.setRequestControls(ctls);

            // initialize counter to total the results
            int totalResults = 0;

            // Search for objects using the filter
            do {
                
             List attributeValues=   LdapUtil.getValueListFromRangedAttrs(ctx, searchBase, searchFilter, searchCtls, -1, -1);
             System.out.println("member size: "+attributeValues.size());
                
//                NamingEnumeration results = ctx.search(searchBase, searchFilter, searchCtls);
//
//                // loop through the results in each page
//                while (results != null && results.hasMoreElements()) {
//                    SearchResult sr = (SearchResult) results.next();
//                    List attrList = LdapContextFactory.getValueListFromAttrs(ctx,searchBase, searchFilter, searchCtls, sr);
//                    // print out the name
//                    System.out.println("name: " + sr.getName() + ", size=" + attrList.size());
//
//                    // increment the counter
//                    totalResults++;
//                }

//                // examine the response controls
//                cookie = parseControls(ctx.getResponseControls());
//                // pass the cookie back to the server for the next page
//                ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
            } while ((cookie != null) && (cookie.length != 0));
            ctx.close();

            System.out.println("Total entries: " + totalResults);
        }

        catch (NamingException e) {
            System.err.println("Paged Search failed." + e);
        } catch (Exception e) {
            System.err.println("Paged Search failed." + e);

        }
    }
    public static final void ldapQueryTest(Hashtable env)  {
        
        LdapContext ctx = null;
        try {
            LdapName ldapName = new LdapName("cn=Group1,ou=Groups,o=TestOrg,dc=my-domain,dc=com");
            searchBase=ldapName.toString();
            searchFilter="(|(uniqueMember=*)(member=*))";

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);

            SearchControls searchCtls = new SearchControls();
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            String returnedAtts[] =  {"member" };
            searchCtls.setReturningAttributes(returnedAtts);
            List vals = LdapUtil.getValueListFromRangedAttrs(ctx, searchBase, searchFilter, searchCtls, -1, -1);

//            
//            NamingEnumeration answer = null;
//            try {
//                answer = ctx.search(searchBase, searchFilter, searchCtls);
//            } catch (NamingException e) {
//                if (logger.isTraceEnabled()) {
//                    logger.error("Unable to find group", e);
//                } else {
//                    logger.error("Unable to find group");
//                }
//                logger.debug("No ldap group found according to the parameters provided");
//            }
//
//            if (answer != null) {
//                while (answer.hasMoreElements()) {
//
//                    SearchResult sr = null;
//                    try {
//                        sr = (SearchResult) answer.next();
//                    } catch (NamingException e) {
//                        logger.error("Failed to search ldap", e);
//                    }
//
//                    System.out.println("name: " + sr.getName());
//
//                    if (sr != null) {
//                        String ldapGroupKey = sr.getNameInNamespace();
//                        Enumeration vals = LdapContextFactory.getValueListFromRangedAttrs(ctx, sr);
//                        HashSet<String> members = new HashSet<String>();
//                        if (vals != null) {
//                            while (vals.hasMoreElements()) {
//
//                                String userKey = (String) vals.nextElement();
//                                members.add(userKey.toLowerCase());
//                            }
//                        } else {
//                            logger.debug("No values found in the attributes list in search result for the group");
//                        }
//                        System.out.println("Username: " + members.size());
//
//                    } else {
//                        logger.debug("No search result found for the group");
//                    }
//                }
//            } else {
//                logger.debug("Search in Ldap returned null");
//            }
            

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ctx.close();
            } catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }
    public static final void ldapPagedQueryTest(Hashtable env) {
        searchBase="dc=my-domain,dc=com";
        searchFilter="cn=*";
        LdapContext ctx = null;
        try {

            // Create the initial directory context
            ctx = new InitialLdapContext(env, null);
            // Create the search controls
            SearchControls searchCtls = new SearchControls();

            // Specify the attributes to return
            String returnedAtts[] = { "member" };
            searchCtls.setReturningAttributes(returnedAtts);

            // Specify the search scope
            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            // Set the page size and initialize the cookie that we pass back in subsequent pages
            int pageSize = 10;
            byte[] cookie = null;

            // Request the paged results control
            Control[] ctls = new Control[] { new PagedResultsControl(pageSize, false) };
            ctx.setRequestControls(ctls);

            // initialize counter to total the results
            int totalResults = 0;

            // Search for objects using the filter
            do {
                NamingEnumeration results = ctx.search(searchBase, searchFilter, searchCtls);

                // loop through the results in each page
                while (results != null && results.hasMoreElements()) {
                    SearchResult searchResult = (SearchResult) results.next();
                    Enumeration userEnumeration = LdapUtil.getValuesFromAttrs(searchResult);
                    //This does move the entire result into memory, however it is only the String names of users
                    List userList = Collections.list(userEnumeration);
                    
                    // print out the name
//                    System.out.println("name: " + searchResult.getName());
                    // increment the counter
                    totalResults++;
                }

                // examine the response controls
                cookie = parseControls(ctx.getResponseControls());
                // pass the cookie back to the server for the next page
                ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
            } while ((cookie != null) && (cookie.length != 0));
            ctx.close();

            System.out.println("Total entries: " + totalResults);
        }

        catch (NamingException e) {
            System.err.println("Paged Search failed." + e);
        } catch (java.io.IOException e) {
            System.err.println("Paged Search failed." + e);

        }
    }


    public static void main(String[] args) {

        Hashtable env = new Hashtable();

         String adminName = "adfshp\\zhang";
        String adminPassword = "1Qazxsw2";
//        String adminName = "CN=PropelAdmin,OU=Propel,OU=Applications,OU=TSLabs,DC=BEL1,DC=global,DC=tslabs,DC=hpecorp,DC=net";
//        String adminPassword = "HPitsm_9";
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

        // set security credentials, note using simple cleartext authentication
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, adminName);
        env.put(Context.SECURITY_CREDENTIALS, adminPassword);

        // connect to my domain controller
        env.put(Context.PROVIDER_URL, "ldap://sgdlitvm0769.adfshp.com:389");
//        env.put(Context.PROVIDER_URL, "ldap://SHCLITVM0624.adfshpe.com:389");
//        env.put(Context.PROVIDER_URL, "ldap://bel1dc1.bel1.global.tslabs.hpecorp.net:389");
        

        activeDirectoryQueryTest(env);
//         activeDirectoryPagedQueryTest(env);
        
//        /////////////////////// Ldap Query
//        env = new Hashtable();
//
//        // String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
//        adminName = "cn=Manager,dc=my-domain,dc=com";
//        adminPassword = "1";
//        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
//
//        // set security credentials, note using simple cleartext authentication
//        env.put(Context.SECURITY_AUTHENTICATION, "simple");
//        env.put(Context.SECURITY_PRINCIPAL, adminName);
//        env.put(Context.SECURITY_CREDENTIALS, adminPassword);
//
//        // connect to my domain controller
//        env.put(Context.PROVIDER_URL, "ldap://16.187.191.233:389");
////
//        ldapQueryTest(env);
////        ldapPagedQueryTest(env);

    }

    static byte[] parseControls(Control[] controls) throws NamingException {
        byte[] cookie = null;
        if (controls != null) {
            for (int i = 0; i < controls.length; i++) {
                if (controls[i] instanceof PagedResultsResponseControl) {
                    PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
                    cookie = prrc.getCookie();
                    System.out.println(">>Next Page \n");
                }
            }
        }
        return (cookie == null) ? new byte[0] : cookie;
    }
}
